-- Copyright (c) 2015,2016 Lucky Byte, Inc.
--
-- Summary : 核心基础函数库
-- 解释器在运行应用脚本之前自动加载此库，因此应用脚本不需要明确的 require
--
-- Author  : 吴小虎 <xiaohu@lucky-byte.com>
-- Since   : 2015.10.18
--
-- History
--  * 2015.10.18 : 创建此文件
--  * 2016.01.18 : 增加 string.pad() 函数
--  * 2016.01.19 : 增加 string.gblen() 函数
--  * 2016.01.22 : 修复 string.pad() 的一个错误
--  * 2016.01.24 : 增加 string.gb() 函数
--  * 2016.05.24 : 改名 string.gb() 为 gb18030.str(), 删除 string.gblen()
--  * 2016.06.20 : 增加 table.strjoin() 函数
--  * 2016.07.16 : 增加 notify 功能
--

-- logger 扩展函数
logger.trace = function(...) logger.log('TRACE', string.format(...)) end
logger.debug = function(...) logger.log('DEBUG', string.format(...)) end
logger.info  = function(...) logger.log('INFO',  string.format(...)) end
logger.warn  = function(...) logger.log('WARN',  string.format(...)) end
logger.error = function(...) logger.log('ERROR', string.format(...)) end
logger.fatal = function(...) logger.log('FATAL', string.format(...)) end

-- 站内通知
notify.info   = function(...) notify.notify(1, string.format(...)) end
notify.warn   = function(...) notify.notify(2, string.format(...)) end
notify.error  = function(...) notify.notify(3, string.format(...)) end
notify.fatal  = function(...) notify.notify(4, string.format(...)) end

-- jdbc 开始/提交/回滚事务
jdbc.begin    = function() jdbc.update('BEGIN') end
jdbc.rollback = function() jdbc.update('ROLLBACK') end
jdbc.commit   = function() jdbc.update('COMMIT') end

-- sleep 函数，通过 java.nio.channels.Selector 实现，不占用 CPU 资源
sleep = function(mills)
    local Selector = luajava.bindClass('java.nio.channels.Selector')
    local selector = Selector:open()
    selector:select(mills)
end

-- 生成 UUID
uuid = function()
    local _uuid = luajava.bindClass('java.util.UUID')
    return _uuid:randomUUID():toString()
end

-- 获取当前日期，YYYY-mm-dd 格式
today = function()
    return os.date('%Y-%m-%d')
end

-- string.split - 分解字符串
-- 参数:
--   string : 待分解字符串
--   delim  : 分隔符，可以为正则表达式
--   limit  : 限制分解数量
--   retain : 当抵达 limit 时，剩余的数据是否保留
-- 返回:
--   数组 table，包含所有分解后的字符串
--
-- 说明:
--    1. limit 和 retain 都是可选的参数，当不提供这些参数时，表示无限制，
--       不保留(没有限制就没有保留)
--
--    2. limit 参数定义限制分解的数量，例如:
--
--         string.split('a:b:c', ':')    -> { 'a', 'b', 'c' }  -- 无限制
--         string.split('a:b:c', ':', 2) -> { 'a', 'b' }       -- 限制两个结果
--
--    3. retain 参数定义是否保留剩余的字符串，例如:
--
--         string.split('a:b:c:d', ':' 3)       -> { 'a', 'b', 'c' }
--         string.split('a:b:c:d', ':' 3, true) -> { 'a', 'b', 'c:d' }
--
--       retain 的情况下，'c:d' 作为一个结果返回，这称为保留.
--
--    4. 空白也是一个元素，例如:
--
--         string.split(':a:b:', ':')  -> { '', 'a', 'b' }
--
--       注意前面的空串保留了，后面的空串未保留，记住这点，否则很容易混淆.
--
string.split = function(string, delim, limit, retain)
    if string.len(delim) == 0 then
        logger.error('分解字符串时，分隔符不能为空.')
        return { string }
    end
    if string.find(string, delim) == nil then
        return { string }
    end
    if limit == nil or limit < 1 then
        limit = 0       -- No limit
    end
    local result = {}
    local fpatt = '(.-)' .. delim
    local last_end = 1
    local n = 0
    while true do
        local st, ed, capt = string.find(string, fpatt, last_end)
        if st == nil then break end
        n = n + 1
        if limit > 0 and n == limit then
            if retain then
                table.insert(result, string.sub(string, st))
            else
                table.insert(result, capt)
            end
            break
        end
        table.insert(result, capt)
        last_end = ed + 1
    end
    if n ~= limit and last_end <= #string then
        capt = string.sub(string, last_end)
        table.insert(result, capt)
    end
    return result
end

-- 去除字符串前后空白字符
string.trim = function(s)
    if not s then return nil end
    return s:match("^%s*(.-)%s*$")
end

-- 去除字符串前后空白字符后的长度
-- 如果参数为 nil，返回 0
string.trimlen = function(s)
    return string.len(string.trim(s) or '')
end

-- 字符串补全
--
-- 参数
--   str      : 字符串
--   size     : 目标长度
--   right    : 右补，可选，默认为 true
--   pad_char : 补充字符，可选，默认为 ' '(空格)
--
string.pad = function(str, size, right, pad_char)
    if right == nil then right = true end
    pad_char = pad_char or ' '
    pad_char = string.sub(pad_char, 1, 1)

    str = tostring(str)
    local _result = string.sub(str, 1, size)
    for i = string.len(str) + 1, size do
        if right == true then
            _result = _result .. pad_char
        else
            _result = pad_char .. _result
        end
    end
    return _result
end

-- table.format 将 lua table 转换成可读的字符串
-- 这个函数仅用于调试
--
-- 参数:
--   table: lua table
-- 返回
--   字符串
--
table.format = function(t)
    if not t then return '' end
    local _kt = {}
    for _key in pairs(t) do
        table.insert(_kt, _key)
    end
    table.sort(_kt)
    local _result = '{\n'
    for _, _k in ipairs(_kt) do
        _result = _result .. "  '" .. tostring(_k) ..
            "' = '" .. tostring(t[_k]) .. "',\n"
    end
    return _result .. '}'
end

-- 整合两个 table，如果两个 table 中有同名 key，使用 t2 中的那个值
table.merge = function(t1, t2)
    for k, v in pairs(t2) do
        t1[k] = v
    end
    return t1
end

-- 检查数组中是否包含指定的值
table.hasv = function(t, v)
    for _, v2 in ipairs(t) do
        if v == v2 then return true end
    end
    return false
end

-- table.strjoin 将 table 转换为 ('item', 'item') 格式的字符串，
-- 转换后字符串可用于 SQL 语句
--
-- 参数:
--   table: lua table
-- 返回
--   字符串
--
table.strjoin = function(t, delimiter)
    local len = #t
    if len == 0 then return "()" end
    delimiter = delimiter or ','
    local _string = "('" .. t[1] .. "'"
    for i = 2, len do
        _string = _string .. delimiter .. "'" .. t[i] .. "'"
    end
    return _string .. ')'
end


-- 四舍五入
--
-- 参数:
--   num : 数值
--   idp : 小数位数(如果为 nil，表示 2)
--
-- 返回:
--   四舍五入后结果
--
function round(num, idp)
    local mult = 10 ^ (idp or 2)
    if num >= 0 then
        return math.floor(num * mult + 0.5) / mult
    else
        return math.ceil(num * mult - 0.5) / mult
    end
end


-- 加载第三方 Lua Libraries
core = core or {}
core.json = require "core.json"
core.date = require "core.date"
core.getopt = require "core.getopt"
